package math

func StringSimilarityRune(s, p string) float32 {
	return RuneSimilarity([]rune(s), []rune(p))
}

func RuneMaxMatch(src, ma []rune) int {
	slen := len(src)
	mlen := len(ma)
	i := 0
	j := 0
	c := 0
	for i < slen && j < mlen {
		if src[i] == ma[j] {
			i++
			j++
			c++
		} else {
			c1 := RuneMaxMatch(src[i+1:], ma[j:])
			c2 := RuneMaxMatch(src[i:], ma[j+1:])
			return c + max(c1, c2)
		}
	}
	return c
}

func RuneSimilarity(src, ma []rune) float32 {
	slen := len(src)
	mlen := len(ma)
	c := RuneMaxMatch(src, ma)
	return float32(c*2) / float32(slen+mlen)
}

/**
 * MatchWildcard: - parse if a string matches given wildcard pattern
 * @pattern: wildcard pattern
 * @str: the string to be parsed
 *
 * Description: Parse the string @str to check if matches wildcard
 * pattern @pattern. The pattern may contain two type wildcardes:
 *   '*' - matches zero or more characters
 *   '?' - matches one character
 * If it's matched, return true, else return false.
 */
func MatchWildcard(pattern, str string) bool {
	return MatchWildcardByte([]byte(pattern), []byte(str))
}

func MatchWildcardByte(pattern, str []byte) bool {
	p := pattern[:]
	s := str[:]
	i := 0
	j := 0
	star := false
	for j < len(s) {
		var c rune = 256
		if i < len(p) {
			c = rune(p[i])
		}
		switch c {
		case '?': //?*与*?效果等同
			i++
			j++
		case '*':
			star = true
			str = s[j:]
			i++
			if i == len(p) {
				return true
			}
			pattern = p[i:]
		default:
			if c == rune(s[j]) {
				i++
				j++
			} else {
				if !star {
					return false
				}
				if len(str) > 0 {
					str = str[1:]
				}
				s = str
				j = 0
				p = pattern
				i = 0
			}
		}
	}
	for i < len(p) && p[i] == '*' {
		i++
	}
	return i == len(p)
}
